package cn.itrip.auth.service;

import cn.itrip.pojo.ItripUser;
import cn.itrip.utlis.DateUtils;
import cn.itrip.utlis.MD5Utils;
import cn.itrip.utlis.RedisUtils;
import cn.itrip.utlis.UserAgentUtil;
import cn.itrip.vo.ItripTokenVO;
import com.alibaba.fastjson.JSON;
import cz.mallat.uasparser.UserAgentInfo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

@Service
public class TokenServiceImpl implements TokenService {

    @Resource
    private RedisUtils redisUtils;
    //生成token默认头
    private final String tokenPrefix = "token:";
    //pc端头
    private final String pcPrefix = "PC-";
    //手机端头
    private final String mobilePrefix = "MOBILE-";

    public RedisUtils getRedisUtils() {
        return redisUtils;
    }

    public void setRedisUtils(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    /**
     * 创建token
     * @param agent
     * @param itripUser
     * @return
     * @throws Exception
     */
    @Override
    public String createToken(String agent, ItripUser itripUser) throws Exception {
        try {
            //判断客户的请求来源是PC还是MOBILE
            UserAgentInfo userAgentInfo = UserAgentUtil.getUasParser().parse(agent);
            StringBuilder stringBuilder = new StringBuilder(tokenPrefix);
            if(userAgentInfo.getDeviceType().equals(UserAgentInfo.UNKNOWN)){
                if (UserAgentUtil.CheckAgent(agent)) {
                    stringBuilder.append(pcPrefix);
                } else {
                    stringBuilder.append(mobilePrefix);
                }

            }else if (userAgentInfo.getDeviceType()
                    .equals("Personal computer")) {
                stringBuilder.append(pcPrefix);
            } else {
                stringBuilder.append(mobilePrefix);
            }
            stringBuilder.append(MD5Utils.getMD5(itripUser.getUsercode(),16)+"-");
            stringBuilder.append(itripUser.getId()+"-");
            stringBuilder.append(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
                    + "-");
            stringBuilder.append(MD5Utils.getMD5(agent,6));
            return stringBuilder.toString();
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception("token生成异常！");
        }
    }

    /**
     * 在redis里保存token
     * @param token
     * @param user
     */
    @Override
    public void save(String token, ItripUser user) {
        if (token.startsWith(tokenPrefix+pcPrefix))
            redisUtils.set(token, JSON.toJSONString(user), TokenService.SESSION_TIMEOUT*1000);//pc端设置一个有效期为2小时的token
        else
            redisUtils.set(token, JSON.toJSONString(user));// 手机认证信息永不失效
    }

    /**
     * 验证token，并判断token是否符合置换条件
     * @param agent
     * @param token
     * @return
     * @throws Exception
     */
    @Override
    public ItripTokenVO verifyToken(String agent, String token) throws Exception {

        String value = redisUtils.getValue(token);
        if(value==null){
           throw new Exception("token不存在，请重新认证！");
        }

        String[] tokenMessger = token.split("-");

        Long generate = DateUtils.getDateMillisecond(tokenMessger[3],"yyyyMMddHHmmss");

        Long passed = Calendar.getInstance().getTimeInMillis()- generate;

        /**
         * 判断是否置换token，若在保护期内则不置换，返回老token
         */
        if(passed < REPLACEMENT_PROTECTION_TIMEOUT){
            return new ItripTokenVO(token,generate+REPLACEMENT_PROTECTION_TIMEOUT,generate);
        }
        ItripUser itripUser = JSON.parseObject(value, ItripUser.class);
        /**
         * 返回新token1
         */
        String newToken = null;
        if(redisUtils.getResidueTime(token)>0 || redisUtils.getResidueTime(token)==-1){
            newToken =  this.createToken(agent,itripUser);
            this.save(newToken,itripUser);
            redisUtils.set(token,value,REPLACEMENT_DELAY);

        }else {
            throw new Exception("过期时间异常，无法置换！");
        }
        return new ItripTokenVO(newToken, Calendar.getInstance().getTimeInMillis()+REPLACEMENT_PROTECTION_TIMEOUT,Calendar.getInstance().getTimeInMillis());
    }

    /**
     * 注销
     * @param token
     * @throws Exception
     */
    @Override
    public void logout(String token) throws Exception {
        redisUtils.delete(token);
    }

    /**
     * 验证token是否存在
     * @param agent
     * @param token
     * @return
     * @throws Exception
     */
    @Override
    public boolean exitToken(String agent, String token) throws Exception {
        String value = redisUtils.getValue(token);
        if(value==null){
            throw new Exception("token不存在，请重新认证！");
        }
        return true;
    }
}
